﻿using System;
using System.Collections.Generic;
using System.Text;
using RoughJs.Ast;

namespace RoughJs.E4X
{
    public abstract class XMLObjectImpl : XMLObject
    {
        private static Object XMLOBJECT_TAG = "XMLObject";
        private XMLLibImpl lib;
        private bool prototypeFlag;

        public XMLObjectImpl(XMLLibImpl lib, Scriptable scope,
                            XMLObject prototype)
        {
            initialize(lib, scope, prototype);
        }
        void initialize(XMLLibImpl lib, Scriptable scope,
                          XMLObject prototype)
        {
            setParentScope(scope);
            setPrototype(prototype);
            prototypeFlag = (prototype == null);
            this.lib = lib;
        }
        public override void setPrototype(Scriptable prototype)
        {
            base.setPrototype(prototype);
        }

        public override void setParentScope(Scriptable parent)
        {

            base.setParentScope(parent);
        }

        public bool isPrototype()
        {
            return prototypeFlag;
        }

        public XMLLibImpl getLib()
        {
            return lib;
        }

        public XML newXML(XmlNode node)
        {
            return lib.newXML(node);
        }

        public XML xmlFromNode(XmlNode node)
        {
            if (node.getXml() == null)
            {
                node.setXml(newXML(node));
            }
            return node.getXml();
        }

        public XMLList newXMLList()
        {
            return lib.newXMLList();
        }

        public XMLList newXMLListFrom(Object o)
        {
            return lib.newXMLListFrom(o);
        }

        public XmlProcessor getProcessor()
        {
            return lib.getProcessor();
        }

        public QName newQName(String uri, String localName, String prefix)
        {
            return lib.newQName(uri, localName, prefix);
        }

        public QName newQName(XmlNode.QName name)
        {
            return lib.newQName(name);
        }

        public Namespace createNamespace(XmlNode.Namespace declaration)
        {
            if (declaration == null) return null;
            return lib.createNamespaces(new XmlNode.Namespace[] { declaration })[0];
        }

        public Namespace[] createNamespaces(XmlNode.Namespace[] declarations)
        {
            return lib.createNamespaces(declarations);
        }


        public override Object get(String name, Scriptable start)
        {
            return base.get(name, start);
        }


        public override bool has(String name, Scriptable start)
        {
            return base.has(name, start);
        }


        public override void put(String name, Scriptable start, Object value)
        {
            base.put(name, start, value);
        }


        public override void delete(String name)
        {
            //    TODO    I am not sure about this, but this is how I found it.  DPC
            throw new ArgumentException("String: [" + name + "]");
        }


        public override Scriptable getPrototype()
        {
            return base.getPrototype();
        }


        //public override void setPrototype(Scriptable prototype)
        //{
        //    base.setPrototype(prototype);
        //}


        public override Scriptable getParentScope()
        {
            return base.getParentScope();
        }


        //public override void setParentScope(Scriptable parent)
        //{
        //    base.setParentScope(parent);
        //}


        public override Object getDefaultValue(Type hint)
        {
            return this.toString();
        }


        public override bool hasInstance(Scriptable scriptable)
        {
            return base.hasInstance(scriptable);
        }

        /**
         * ecmaHas(cx, id) calls this after resolving when id to XMLName
         * and checking it is not Uint32 index.
         */
       public abstract bool hasXMLProperty(XMLName name);

        /**
         * ecmaGet(cx, id) calls this after resolving when id to XMLName
         * and checking it is not Uint32 index.
         */
       public abstract Object getXMLProperty(XMLName name);

        /**
         * ecmaPut(cx, id, value) calls this after resolving when id to XMLName
         * and checking it is not Uint32 index.
         */
       public abstract void putXMLProperty(XMLName name, Object value);

        /**
         * ecmaDelete(cx, id) calls this after resolving when id to XMLName
         * and checking it is not Uint32 index.
         */
      public  abstract void deleteXMLProperty(XMLName name);

        /**
         * Test XML equality with target the target.
         */
      public  abstract bool equivalentXml(Object target);

       public abstract void addMatches(XMLList rv, XMLName name);

        private XMLList getMatches(XMLName name)
        {
            XMLList rv = newXMLList();
            addMatches(rv, name);
            return rv;
        }

        public abstract XML getXML();

        // Methods from section 12.4.4 in the spec
        public abstract XMLList child(int index);
        public abstract XMLList child(XMLName xmlName);
        public abstract XMLList children();
        public abstract XMLList comments();
        public abstract bool  contains(Object xml);
        public abstract XMLObjectImpl copy();
        public abstract XMLList elements(XMLName xmlName);
        public abstract bool  hasOwnProperty(XMLName xmlName);
        public abstract bool  hasComplexContent();
        public abstract bool  hasSimpleContent();
        public abstract int length();
        public abstract void normalize();
        public abstract Object parent();
        public abstract XMLList processingInstructions(XMLName xmlName);
        public abstract bool  propertyIsEnumerable(Object member);
        public abstract XMLList text();

        public abstract String toString();
        public abstract String toSource(int indent);
        public abstract String toXMLString();
        public abstract Object valueOf();

        public abstract Object jsConstructor(Context cx, bool inNewExpr, Object[] args);

        public Object getMethod(String id)
        {
            return base.get(id, this);
        }

         /**
     * XMLObject always compare with any value and equivalentValues
     * never returns {@link Scriptable#NOT_FOUND} for them but rather
     * calls equivalentXml(value) and wrap the result as Boolean.
     */

    public override  Object equivalentValues(Object value) {
        bool  result = equivalentXml(value);
        return result ?true : false;
    }

    public override  bool  ecmaHas(Context cx, Object id) {
        if (cx == null) cx = Context.getCurrentContext();
        XMLName xmlName = lib.toXMLNameOrIndex(cx, id);
        if (xmlName == null) {
            long index = ScriptRuntime.lastUint32Result(cx);
            // XXX Fix this cast
            return has((int)index, this);
        }
        return hasXMLProperty(xmlName);
    }

    public override  Object ecmaGet(Context cx, Object id) {
        if (cx == null) cx = Context.getCurrentContext();
        XMLName xmlName = lib.toXMLNameOrIndex(cx, id);
        if (xmlName == null) {
            long index = ScriptRuntime.lastUint32Result(cx);
            // XXX Fix this cast
            Object result = get((int)index, this);
            if (result == ScriptableObject.NOT_FOUND) {
                result = Undefined.instance;
            }
            return result;
        }
        return getXMLProperty(xmlName);
    }

    /**
     * Implementation of ECMAScript [[Put]]
     */

    public override  void ecmaPut(Context cx, Object id, Object value) {
        if (cx == null) cx = Context.getCurrentContext();
        XMLName xmlName = lib.toXMLNameOrIndex(cx, id);
        if (xmlName == null) {
            long index = ScriptRuntime.lastUint32Result(cx);
            // XXX Fix this cast
            put((int)index, this, value);
            return;
        }
        putXMLProperty(xmlName, value);
    }


    public override  bool  ecmaDelete(Context cx, Object id) {
        if (cx == null) cx = Context.getCurrentContext();
        XMLName xmlName = lib.toXMLNameOrIndex(cx, id);
        if (xmlName == null) {
            long index = ScriptRuntime.lastUint32Result(cx);
            // XXX Fix this
            delete((int)index);
            return true;
        }
        deleteXMLProperty(xmlName);
        return true;
    }

    //    TODO    Can this be made more strongly typed?

    public override Ref memberRef(Context cx, Object elem, int memberTypeFlags) {
        bool  attribute = (memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0;
        bool  descendants = (memberTypeFlags & Node.DESCENDANTS_FLAG) != 0;
        if (!attribute && !descendants) {
            // Code generation would use ecma(Get|Has|Delete|Set) for
            // normal name identifiers so one ATTRIBUTE_FLAG
            // or DESCENDANTS_FLAG has to be set
            throw Kit.codeBug();
        }
        XmlNode.QName qname = lib.toNodeQName(cx, elem, attribute);
        XMLName rv = XMLName.create(qname, attribute, descendants);
        rv.initXMLObject(this);
        return rv;
    }

    /**
     * Generic reference to implement x::ns, x.@ns::y, x..@ns::y etc.
     */

    public override Ref memberRef(Context cx, Object namespace1, Object elem,
            int memberTypeFlags)
    {
        bool  attribute = (memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0;
        bool  descendants = (memberTypeFlags & Node.DESCENDANTS_FLAG) != 0;
        XMLName rv = XMLName.create(lib.toNodeQName(cx, namespace1, elem),
                attribute, descendants);
        rv.initXMLObject(this);
        return rv;
    }

 
    public override NativeWith enterWith(Scriptable scope) {
        return new XMLWithScope(lib, scope, this);
    }

    
    public override NativeWith enterDotQuery(Scriptable scope) {
        XMLWithScope xws = new XMLWithScope(lib, scope, this);
        xws.initAsDotQuery();
        return xws;
    }


    public override  Object addValues(Context cx, bool  thisIsLeft,
        Object value) {
        if (value is XMLObject) {
            XMLObject v1, v2;
            if (thisIsLeft) {
                v1 = this;
                v2 = (XMLObject)value;
            } else {
                v1 = (XMLObject)value;
                v2 = this;
            }
            return lib.addXMLObjects(cx, v1, v2);
        }
        if (value == Undefined.instance) {
            // both "xml + undefined" and "undefined + xml" gives String(xml)
            return ScriptRuntime.toString(this);
        }

        return base.addValues(cx, thisIsLeft, value);
    }

    //
    //
    // IdScriptableObject machinery
    //
    //

     public void exportAsJSClass(bool sealed1) {
        prototypeFlag = true;
        exportAsJSClass(MAX_PROTOTYPE_ID, getParentScope(), sealed1);
    }

// #string_id_map#
    private  const int
        Id_constructor             = 1,

        Id_addNamespace            = 2,
        Id_appendChild             = 3,
        Id_attribute               = 4,
        Id_attributes              = 5,
        Id_child                   = 6,
        Id_childIndex              = 7,
        Id_children                = 8,
        Id_comments                = 9,
        Id_contains                = 10,
        Id_copy                    = 11,
        Id_descendants             = 12,
        Id_elements                = 13,
        Id_inScopeNamespaces       = 14,
        Id_insertChildAfter        = 15,
        Id_insertChildBefore       = 16,
        Id_hasOwnProperty          = 17,
        Id_hasComplexContent       = 18,
        Id_hasSimpleContent        = 19,
        Id_length                  = 20,
        Id_localName               = 21,
        Id_name                    = 22,
        Id_namespace               = 23,
        Id_namespaceDeclarations   = 24,
        Id_nodeKind                = 25,
        Id_normalize               = 26,
        Id_parent                  = 27,
        Id_prependChild            = 28,
        Id_processingInstructions  = 29,
        Id_propertyIsEnumerable    = 30,
        Id_removeNamespace         = 31,
        Id_replace                 = 32,
        Id_setChildren             = 33,
        Id_setLocalName            = 34,
        Id_setName                 = 35,
        Id_setNamespace            = 36,
        Id_text                    = 37,
        Id_toString                = 38,
        Id_toSource                = 39,
        Id_toXMLString             = 40,
        Id_valueOf                 = 41,

        MAX_PROTOTYPE_ID           = 41;

   public override int findPrototypeId(String s) {
        int id;

          id = 0; String X = null; int c;
            switch (s.Length) {
            case 4: c=s.ToCharArray()[0];
                if (c=='c') { X="copy";id=Id_copy; }
                else if (c=='n') { X="name";id=Id_name; }
                else if (c=='t') { X="text";id=Id_text; }
                goto L;
            case 5: X="child";id=Id_child; goto L;
            case 6: c=s.ToCharArray()[0];
                if (c=='l') { X="length";id=Id_length; }
                else if (c=='p') { X="parent";id=Id_parent; }
                goto L;
            case 7: c=s.ToCharArray()[0];
                if (c=='r') { X="replace";id=Id_replace; }
                else if (c=='s') { X="setName";id=Id_setName; }
                else if (c=='v') { X="valueOf";id=Id_valueOf; }
                goto L;
            case 8: switch (s.ToCharArray()[2]) {
                case 'S': c=s.ToCharArray()[7];
                    if (c=='e') { X="toSource";id=Id_toSource; }
                    else if (c=='g') { X="toString";id=Id_toString; }
                    goto L;
                case 'd': X="nodeKind";id=Id_nodeKind; goto L;
                case 'e': X="elements";id=Id_elements; goto L;
                case 'i': X="children";id=Id_children; goto L;
                case 'm': X="comments";id=Id_comments; goto L;
                case 'n': X="contains";id=Id_contains; goto L;
                } goto L;
            case 9: switch (s.ToCharArray()[2]) {
                case 'c': X="localName";id=Id_localName; goto L;
                case 'm': X="namespace";id=Id_namespace; goto L;
                case 'r': X="normalize";id=Id_normalize; goto L;
                case 't': X="attribute";id=Id_attribute; goto L;
                } goto L;
            case 10: c=s.ToCharArray()[0];
                if (c=='a') { X="attributes";id=Id_attributes; }
                else if (c=='c') { X="childIndex";id=Id_childIndex; }
                goto L;
            case 11: switch (s.ToCharArray()[0]) {
                case 'a': X="appendChild";id=Id_appendChild; goto L;
                case 'c': X="constructor";id=Id_constructor; goto L;
                case 'd': X="descendants";id=Id_descendants; goto L;
                case 's': X="setChildren";id=Id_setChildren; goto L;
                case 't': X="toXMLString";id=Id_toXMLString; goto L;
                } goto L;
            case 12: c=s.ToCharArray()[0];
                if (c=='a') { X="addNamespace";id=Id_addNamespace; }
                else if (c=='p') { X="prependChild";id=Id_prependChild; }
                else if (c=='s') {
                    c=s.ToCharArray()[3];
                    if (c=='L') { X="setLocalName";id=Id_setLocalName; }
                    else if (c=='N') { X="setNamespace";id=Id_setNamespace; }
                }
                goto L;
            case 14: X="hasOwnProperty";id=Id_hasOwnProperty; goto L;
            case 15: X="removeNamespace";id=Id_removeNamespace; goto L;
            case 16: c=s.ToCharArray()[0];
                if (c=='h') { X="hasSimpleContent";id=Id_hasSimpleContent; }
                else if (c=='i') { X="insertChildAfter";id=Id_insertChildAfter; }
                goto L;
            case 17: c=s.ToCharArray()[3];
                if (c=='C') { X="hasComplexContent";id=Id_hasComplexContent; }
                else if (c=='c') { X="inScopeNamespaces";id=Id_inScopeNamespaces; }
                else if (c=='e') { X="insertChildBefore";id=Id_insertChildBefore; }
                goto L;
            case 20: X="propertyIsEnumerable";id=Id_propertyIsEnumerable; goto L;
            case 21: X="namespaceDeclarations";id=Id_namespaceDeclarations; goto L;
            case 22: X="processingInstructions";id=Id_processingInstructions; goto L;
            }
       L: ;
            if (X!=null && X!=s && !(X==s)) id = 0;
            goto L0;
        L0:;

        return id;
    }



    public override void initPrototypeId(int id) {
        String s;
        int arity;
        switch (id) {
            case Id_constructor: {
                IdFunctionObject ctor;
                if (this is XML) {
                    ctor = new XMLCtor((XML)this, XMLOBJECT_TAG, id, 1);
                } else {
                    ctor = new IdFunctionObject(this, XMLOBJECT_TAG, id, 1);
                }
                initPrototypeConstructor(ctor);
                return;
            }

            case Id_addNamespace:      arity=1; s="addNamespace";      break;
            case Id_appendChild:       arity=1; s="appendChild";       break;
            case Id_attribute:         arity=1; s="attribute";         break;
            case Id_attributes:        arity=0; s="attributes";        break;
            case Id_child:             arity=1; s="child";             break;
            case Id_childIndex:        arity=0; s="childIndex";        break;
            case Id_children:          arity=0; s="children";          break;
            case Id_comments:          arity=0; s="comments";          break;
            case Id_contains:          arity=1; s="contains";          break;
            case Id_copy:              arity=0; s="copy";              break;
            case Id_descendants:       arity=1; s="descendants";       break;
            case Id_elements:          arity=1; s="elements";          break;
            case Id_hasComplexContent: arity=0; s="hasComplexContent"; break;
            case Id_hasOwnProperty:    arity=1; s="hasOwnProperty";    break;
            case Id_hasSimpleContent:  arity=0; s="hasSimpleContent";  break;
            case Id_inScopeNamespaces: arity=0; s="inScopeNamespaces"; break;
            case Id_insertChildAfter:  arity=2; s="insertChildAfter";  break;
            case Id_insertChildBefore: arity=2; s="insertChildBefore"; break;
            case Id_length:            arity=0; s="length";            break;
            case Id_localName:         arity=0; s="localName";         break;
            case Id_name:              arity=0; s="name";              break;
            case Id_namespace:         arity=1; s="namespace";         break;
            case Id_namespaceDeclarations:
                arity=0; s="namespaceDeclarations"; break;
            case Id_nodeKind:          arity=0; s="nodeKind";          break;
            case Id_normalize:         arity=0; s="normalize";         break;
            case Id_parent:            arity=0; s="parent";            break;
            case Id_prependChild:      arity=1; s="prependChild";      break;
            case Id_processingInstructions:
                arity=1; s="processingInstructions"; break;
            case Id_propertyIsEnumerable:
                arity=1; s="propertyIsEnumerable"; break;
            case Id_removeNamespace:   arity=1; s="removeNamespace";   break;
            case Id_replace:           arity=2; s="replace";           break;
            case Id_setChildren:       arity=1; s="setChildren";       break;
            case Id_setLocalName:      arity=1; s="setLocalName";      break;
            case Id_setName:           arity=1; s="setName";           break;
            case Id_setNamespace:      arity=1; s="setNamespace";      break;
            case Id_text:              arity=0; s="text";              break;
            case Id_toString:          arity=0; s="toString";          break;
            case Id_toSource:          arity=1; s="toSource";          break;
            case Id_toXMLString:       arity=1; s="toXMLString";       break;
            case Id_valueOf:           arity=0; s="valueOf";           break;

            default: throw new ArgumentException(id.ToString());
        }
        initPrototypeMethod(XMLOBJECT_TAG, id, s, arity);
    }

    private Object[] toObjectArray(Object[] typed) {
        Object[] rv = new Object[typed.Length];
        for (int i=0; i<rv.Length; i++) {
            rv[i] = typed[i];
        }
        return rv;
    }

    private void xmlMethodNotFound(Object object1, String name) {
        throw ScriptRuntime.notFunctionError(object1, name);
    }

    public override Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
                             Scriptable thisObj, Object[] args)
    {
        if (!f.hasTag(XMLOBJECT_TAG)) {
            return base.execIdCall(f, cx, scope, thisObj, args);
        }
        int id = f.methodId();
        if (id == Id_constructor) {
            return jsConstructor(cx, thisObj == null, args);
        }

        // All (XML|XMLList).prototype methods require thisObj to be XML
        if (!(thisObj is XMLObjectImpl))
            throw incompatibleCallError(f);
        XMLObjectImpl realThis = (XMLObjectImpl)thisObj;

        XML xml = realThis.getXML();
        switch (id) {
            case Id_appendChild: {
                if (xml == null) xmlMethodNotFound(realThis, "appendChild");
                return xml.appendChild(arg1(args, 0));
            }
            case Id_addNamespace: {
                if (xml == null) xmlMethodNotFound(realThis, "addNamespace");
                Namespace ns = lib.castToNamespace(cx, arg1(args, 0));
                return xml.addNamespace(ns);
            }
            case Id_childIndex: {
                if (xml == null) xmlMethodNotFound(realThis, "childIndex");
                return ScriptRuntime.wrapInt(xml.childIndex());
            }
            case Id_inScopeNamespaces: {
                if (xml == null) xmlMethodNotFound(realThis, "inScopeNamespaces");
                return cx.newArray(scope, toObjectArray(xml.inScopeNamespaces()));
            }
            case Id_insertChildAfter: {
                if (xml == null) xmlMethodNotFound(realThis, "insertChildAfter");
                Object arg0 = arg1(args, 0);
                if (arg0 == null || arg0 is XML) {
                    return xml.insertChildAfter((XML)arg0, arg1(args, 1));
                }
                return Undefined.instance;
            }
            case Id_insertChildBefore: {
                if (xml == null) xmlMethodNotFound(realThis, "insertChildBefore");
                Object arg0 = arg1(args, 0);
                if (arg0 == null || arg0 is XML) {
                    return xml.insertChildBefore((XML)arg0, arg1(args, 1));
                }
                return Undefined.instance;
            }
            case Id_localName: {
                if (xml == null) xmlMethodNotFound(realThis, "localName");
                return xml.localName();
            }
            case Id_name: {
                if (xml == null) xmlMethodNotFound(realThis, "name");
                return xml.name();
            }
            case Id_namespace: {
                if (xml == null) xmlMethodNotFound(realThis, "namespace");
                String prefix = (args.Length > 0) ? ScriptRuntime.toString(args[0]) : null;
                Namespace rv = xml.namespace1(prefix);
                if (rv == null) {
                    return Undefined.instance;
                } else {
                    return rv;
                }
            }
            case Id_namespaceDeclarations: {
                if (xml == null) xmlMethodNotFound(realThis, "namespaceDeclarations");
                Namespace[] array = xml.namespaceDeclarations();
                return cx.newArray(scope, toObjectArray(array));
            }
            case Id_nodeKind: {
                if (xml == null) xmlMethodNotFound(realThis, "nodeKind");
                return xml.nodeKind();
            }
            case Id_prependChild: {
                if (xml == null) xmlMethodNotFound(realThis, "prependChild");
                return xml.prependChild(arg1(args, 0));
            }
            case Id_removeNamespace: {
                if (xml == null) xmlMethodNotFound(realThis, "removeNamespace");
                Namespace ns = lib.castToNamespace(cx, arg1(args, 0));
                return xml.removeNamespace(ns);
            }
            case Id_replace: {
                if (xml == null) xmlMethodNotFound(realThis, "replace");
                XMLName xmlName = lib.toXMLNameOrIndex(cx, arg1(args, 0));
                Object arg = arg1(args, 1);
                if (xmlName == null) {
                    //    I refuse to believe that this number will exceed 2^31
                    int index = (int)ScriptRuntime.lastUint32Result(cx);
                    return xml.replace(index, arg);
                } else {
                    return xml.replace(xmlName, arg);
                }
            }
            case Id_setChildren: {
                if (xml == null) xmlMethodNotFound(realThis, "setChildren");
                return xml.setChildren(arg1(args, 0));
            }
            case Id_setLocalName: {
                if (xml == null) xmlMethodNotFound(realThis, "setLocalName");
                String localName;
                Object arg = arg1(args, 0);
                if (arg is QName) {
                    localName = ((QName)arg).localName();
                } else {
                    localName = ScriptRuntime.toString(arg);
                }
                xml.setLocalName(localName);
                return Undefined.instance;
            }
            case Id_setName: {
                if (xml == null) xmlMethodNotFound(realThis, "setName");
                Object arg = (args.Length != 0) ? args[0] : Undefined.instance;
                QName qname = lib.constructQName(cx, arg);
                xml.setName(qname);
                return Undefined.instance;
            }
            case Id_setNamespace: {
                if (xml == null) xmlMethodNotFound(realThis, "setNamespace");
                Namespace ns = lib.castToNamespace(cx, arg1(args, 0));
                xml.setNamespace(ns);
                return Undefined.instance;
            }

            case Id_attribute: {
                XMLName xmlName = XMLName.create( lib.toNodeQName(cx, arg1(args, 0), true), true, false );
                return realThis.getMatches(xmlName);
            }
            case Id_attributes:
                return realThis.getMatches(XMLName.create(XmlNode.QName.create(null, null), true, false));
            case Id_child: {
                XMLName xmlName = lib.toXMLNameOrIndex(cx, arg1(args, 0));
                if (xmlName == null) {
                    //    Two billion or so is a fine upper limit, so we cast to int
                    int index = (int)ScriptRuntime.lastUint32Result(cx);
                    return realThis.child(index);
                } else {
                    return realThis.child(xmlName);
                }
            }
            case Id_children:
                return realThis.children();
            case Id_comments:
                return realThis.comments();
            case Id_contains:
                return ScriptRuntime.wrapBoolean(
                    realThis.contains(arg1(args, 0)));
            case Id_copy:
                return realThis.copy();
            case Id_descendants: {
                XmlNode.QName qname = (args.Length == 0) ? XmlNode.QName.create(null, null) : lib.toNodeQName(cx, args[0], false);
                return realThis.getMatches( XMLName.create(qname, false, true) );
            }
            case Id_elements: {
                XMLName xmlName = (args.Length == 0)
                ? XMLName.formStar()
                : lib.toXMLName(cx, args[0]);
                return realThis.elements(xmlName);
            }
            case Id_hasOwnProperty: {
                XMLName xmlName = lib.toXMLName(cx, arg1(args, 0));
                return ScriptRuntime.wrapBoolean(
                    realThis.hasOwnProperty(xmlName));
            }
            case Id_hasComplexContent:
                return ScriptRuntime.wrapBoolean(realThis.hasComplexContent());
            case Id_hasSimpleContent:
                return ScriptRuntime.wrapBoolean(realThis.hasSimpleContent());
            case Id_length:
                return ScriptRuntime.wrapInt(realThis.length());
            case Id_normalize:
                realThis.normalize();
                return Undefined.instance;
            case Id_parent:
                return realThis.parent();
            case Id_processingInstructions: {
                XMLName xmlName = (args.Length > 0)
                ? lib.toXMLName(cx, args[0])
                : XMLName.formStar();
                return realThis.processingInstructions(xmlName);
            }
            case Id_propertyIsEnumerable: {
                return ScriptRuntime.wrapBoolean(
                    realThis.propertyIsEnumerable(arg1(args, 0)));
            }
            case Id_text:
                return realThis.text();
            case Id_toString:
                return realThis.toString();
            case Id_toSource:
                int indent = ScriptRuntime.toInt32(args, 0);
                return realThis.toSource(indent);
            case Id_toXMLString: {
                return realThis.toXMLString();
            }
            case Id_valueOf:
                return realThis.valueOf();
        }
        throw new ArgumentException(id.ToString());
    }

    private static Object arg1(Object[] args, int i) {
        return (i < args.Length) ? args[i] : Undefined.instance;
    }

    public XML newTextElementXML(XmlNode reference, XmlNode.QName qname, String value)
    {
        return lib.newTextElementXML(reference, qname, value);
    }

    
     public XML newXMLFromJs(Object inputObject)
     {
        return lib.newXMLFromJs(inputObject);
    }

     public XML ecmaToXml(Object object1)
     {
        return lib.ecmaToXml(object1);
    }

   public  String ecmaEscapeAttributeValue(String s) {

        String quoted = lib.escapeAttributeValue(s);
        return quoted.Substring(1, quoted.Length - 1);
    }

   public XML createEmptyXML()
   {
        return newXML(XmlNode.createEmpty(getProcessor()));
    }

    }// end for class
}
